{
  lib,
  runtimeShell,
  srcOnly,
  stdenvNoCC,
  writeTextFile,
  writeShellScript,
  path,
  bubblewrap,
  coreutils,
  curl,
  jq,
  mitm-cache,
  nix,
  openssl,
  procps,
  python3,
}:

lib.makeOverridable (
  {
    pkg,
    pname,
    attrPath,
    bwrapFlags,
    data,
    silent,
    useBwrap,
  }:
  let
    keep = [
      "MITM_CACHE_HOST"
      "MITM_CACHE_PORT"
      "MITM_CACHE_ADDRESS"
      "MITM_CACHE_CA"
      "MITM_CACHE_CERT_DIR"
    ];
    gradleScript = writeShellScript "gradle-commands.sh" ''
      set -eo pipefail
      export http_proxy="$MITM_CACHE_ADDRESS"
      export https_proxy="$MITM_CACHE_ADDRESS"
      export SSL_CERT_FILE="$MITM_CACHE_CA"
      export NIX_SSL_CERT_FILE="$MITM_CACHE_CA"
      export GRADLE_USER_HOME="$(${coreutils}/bin/mktemp -d)"
      export IN_GRADLE_UPDATE_DEPS=1
      trap "${coreutils}/bin/rm -rf '$GRADLE_USER_HOME'" SIGINT SIGTERM ERR EXIT
      cd "$(${coreutils}/bin/mktemp -d)"
      ${coreutils}/bin/mkdir out
      export out="$PWD/out"
      trap "${coreutils}/bin/rm -rf '$PWD'" SIGINT SIGTERM ERR EXIT
      source "$stdenv/setup"
      phases="''${prePhases[*]:-} unpackPhase patchPhase ''${preConfigurePhases[*]:-} configurePhase gradleUpdateScript" genericBuild
    '';
    source = srcOnly (
      pkg.overrideAttrs (old: {
        mitmCache = "";
        gradleInitScript = ./init-deps.gradle;

        stdenv = old.stdenv or stdenvNoCC;
      })
    );
    sourceDrvPath = builtins.unsafeDiscardOutputDependency source.drvPath;
    nixShellKeep = lib.concatMapStringsSep " " (x: "--keep ${x}") keep;
  in
  writeTextFile {
    name = "fetch-deps.sh";
    executable = true;
    # see pkgs/common-updater/combinators.nix
    derivationArgs.passthru = {
      supportedFeatures = lib.optional silent "silent";
    }
    // lib.optionalAttrs (attrPath != null) { inherit attrPath; };
    text = ''
      #!${runtimeShell}
      set -eo pipefail
      export PATH="${
        lib.makeBinPath (
          [
            coreutils
            curl
            jq
            mitm-cache
            openssl
            procps
            python3.pkgs.ephemeral-port-reserve
          ]
          ++ lib.optional useBwrap bubblewrap
        )
      }:$PATH"
      outPath="${
        # if this is an absolute path in nix store, use path relative to the store path
        if lib.hasPrefix "${builtins.storeDir}/" (toString data) then
          builtins.concatStringsSep "/" (
            lib.drop 1 (lib.splitString "/" (lib.removePrefix "${builtins.storeDir}/" (toString data)))
          )
        # if this is an absolute path anywhere else, just use that path
        else if lib.hasPrefix "/" (toString data) then
          toString data
        # otherwise, use a path relative to the package
        else
          "${dirOf pkg.meta.position}/${data}"
      }"

      pushd "$(mktemp -d)" >/dev/null
      MITM_CACHE_DIR="$PWD"
      trap "rm -rf '$MITM_CACHE_DIR'" SIGINT SIGTERM ERR EXIT
      openssl genrsa -out ca.key 2048
      openssl req -x509 -new -nodes -key ca.key -sha256 -days 1 -out ca.cer -subj "/C=AL/ST=a/L=a/O=a/OU=a/CN=example.org"
      export MITM_CACHE_HOST=127.0.0.1
      export MITM_CACHE_PORT="''${mitmCachePort:-$(ephemeral-port-reserve "$MITM_CACHE_HOST")}"
      export MITM_CACHE_ADDRESS="$MITM_CACHE_HOST:$MITM_CACHE_PORT"
      # forget all redirects - this makes the lockfiles predictable
      # not only does this strip CDN URLs, but it also improves security - since the redirects aren't
      # stored in the lockfile, a malicious actor can't change the redirect URL stored in the lockfile
      mitm-cache \
        -l"$MITM_CACHE_ADDRESS" \
        record \
        --reject '\.(md5|sha(1|256|512:?):?)$' \
        --forget-redirects-from '.*' \
        --record-text '/maven-metadata\.xml$' >/dev/null 2>/dev/null &
      MITM_CACHE_PID="$!"
      # wait for mitm-cache to fully start
      for i in {0..20}; do
        kill -0 "$MITM_CACHE_PID" 2>/dev/null || (echo "Failed to start mitm-cache" && exit 1)
        curl -so/dev/null "$MITM_CACHE_ADDRESS" && break
        [[ "$i" -eq 20 ]] && (echo "Failed to start mitm-cache" && exit 1)
        sleep 0.5
      done
      trap "kill '$MITM_CACHE_PID'" SIGINT SIGTERM ERR EXIT
      export MITM_CACHE_CERT_DIR="$PWD"
      export MITM_CACHE_CA="$MITM_CACHE_CERT_DIR/ca.cer"
      popd >/dev/null
      useBwrap="''${USE_BWRAP:-${toString useBwrap}}"
      if [ -n "$useBwrap" ]; then
        # bwrap isn't necessary, it's only used to prevent messy build scripts from touching ~
        bwrap \
          --unshare-all --share-net --clearenv --chdir / --setenv HOME /homeless-shelter \
          --tmpfs /home --bind /tmp /tmp --ro-bind /nix /nix --ro-bind /run /run --proc /proc --dev /dev  \
          --ro-bind ${toString path} ${toString path} --bind "$MITM_CACHE_CERT_DIR" "$MITM_CACHE_CERT_DIR" \
          ${builtins.concatStringsSep " " (map (x: "--setenv ${x} \"\$${x}\"") keep)} \
          --setenv NIX_BUILD_SHELL ${runtimeShell} ${bwrapFlags} ''${BWRAP_FLAGS:-} \
          -- ${nix}/bin/nix-shell --pure --run ${gradleScript} ${nixShellKeep} ${sourceDrvPath}
      else
        NIX_BUILD_SHELL=${runtimeShell} nix-shell --pure --run ${gradleScript} ${nixShellKeep} ${sourceDrvPath}
      fi${lib.optionalString silent " >&2"}
      kill -s SIGINT "$MITM_CACHE_PID"
      for i in {0..20}; do
        # check for valid json
        if jq -e 1 "$MITM_CACHE_DIR/out.json" >/dev/null 2>/dev/null; then
          exec ${python3.interpreter} ${./compress-deps-json.py} "$MITM_CACHE_DIR/out.json" "$outPath"
        fi
        sleep 1
      done
      exit 1
    '';
  }
)
